<?php declare(strict_types=1);

use Hyperf\DbConnection\Db;
use Hyperf\Redis\Redis;
use Hyperf\Framework\Logger\StdoutLogger;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;


if (!function_exists('di')) {
    function di($id = null)
    {
        $container = \Hyperf\Context\ApplicationContext::getContainer();
        if ($id) {
            return $container->get($id);
        }

        return $container;
    }
}
if (!function_exists('env')) {
    function env($key, $default = null)
    {
        return \Hyperf\Support\env($key, $default);
    }
}
if (!function_exists('make')) {
    function make(string $name, array $parameters = [])
    {
        return \Hyperf\Support\make($name, $parameters);
    }
}
if (!function_exists('config')) {
    function config(string $key, mixed $default = null): mixed
    {
        return \Hyperf\Config\config($key, $default);
    }
}

defined('IS_PROD') || define('IS_PROD', env('APP_ENV') === 'prod');

if (!function_exists('getDependContent')) {
    /**
     * 获取依赖文件的内容
     * @param string $depend
     * @return false|mixed|string
     */
    function getDependContent(string $depend): mixed
    {
        $fullPath = rtrim(env('DEPENDS_FOLDER'), '/') . '/' . ltrim($depend, '/');
        $content = file_get_contents($fullPath);
        try {
            return json_decode($content, true);
        } catch (\Throwable $throwable) {
            return $content;
        }
    }
}

if (!function_exists('getExInfo')) {
    function getExInfo(\Throwable $ex): array
    {
        $code = $ex->getCode();
        $file = $ex->getFile() . ":" . $ex->getLine();
        $error = $ex->getMessage();
        return compact('code', 'file', 'error');
    }
}

if (!function_exists('getErrStr')) {
    function getErrStr(\Throwable $ex): string
    {
        return sprintf("%s in [%s] \n\t  %s \n", ...array_values(getExInfo($ex)));
    }
}

if (!function_exists('getTableList')) {
    function getTableList(string $pool, string $tablePrefix): array
    {
        $tableList = Db::connection($pool)->select("show tables like '{$tablePrefix}_______'");
        foreach ($tableList as &$table) $table = array_values((array)$table)[0];
        return $tableList;
    }
}

if (!function_exists('getLogger')) {
    function getLogger(string $group = 'default', string $name = 'log'): LoggerInterface
    {
        return make(Hyperf\Logger\LoggerFactory::class)->get($name, $group);
    }
}

if (!function_exists('stdPrinter')) {

    function stdPrinter(): StdoutLogger
    {
        return Hyperf\Support\make(StdoutLogger::class);
    }
}

if (!function_exists('getRedis')) {
    function getRedis()
    {
        return Hyperf\Support\make(Redis::class);
    }
}

if (!function_exists('formatLogArray')) {
    function formatLogArray(array $array): string
    {
        if (empty($array)) return '';
        $stringArr = [];
        foreach ($array as $key => $val) {
            $valStr = '';
            if (is_array($val)) {
                if (!empty($val)) {
                    if (count($val) > 1) {
                        $valStr = json_encode($val, JSON_UNESCAPED_UNICODE);
                    } else {
                        $valStr = (is_array($val[0]) ? json_encode($val[0], JSON_UNESCAPED_UNICODE) : @(string)$val[0]);
                    }
                }
            } elseif (is_object($val)) {
                $valStr = @$val->__toString();
            } else {
                $valStr = $val;
            }
            $stringArr[] = "\"{$key}\":\"{$valStr}\"";
        }
        return implode('; ', $stringArr);
    }
}

if (!function_exists('phoneValidate')) {

    function phoneValidate(string $phone): bool
    {
        return patternValidate('/^1[3-9]\d{9}$/', $phone);
    }
}

if (!function_exists('patternValidate')) {

    function patternValidate(string $pattern, string $account): bool
    {
        return (bool)preg_match($pattern, $account);
    }
}

if (!function_exists('getMonthRange')) {
    /**
     * 根据时间戳获取当月的开始时间&结束时间.
     */
    function getMonthRange(int $timestamp = null): array
    {
        $time = is_null($timestamp) ? time() : $timestamp;
        $startDate = date('Y-m-01 00:00:00', $time);
        return [strtotime($startDate), strtotime("{$startDate} +1 month -1 day") + 86399];
    }
}

if (!function_exists('requestIp')) {
    /**
     * 获取请求IP.
     * @return mixed|string
     */
    function requestIp(): mixed
    {
        $request = Hyperf\Support\make(ServerRequestInterface::class);
        $headers = $request->getHeaders();
        if (!empty($headers['x-forwarded-for'][0])) {
            return $headers['x-forwarded-for'][0];
        }
        if (!empty($headers['x-real-ip'][0])) {
            return $headers['x-real-ip'][0];
        }
        $serverParams = $request->getServerParams();
        return $serverParams['remote_addr'] ?? '';
    }
}

if (!function_exists('handleTreeList')) {

    /**
     * 建立数组树结构列表
     * @param array|null $arr
     * @param int $pid 父级id
     * @param int $depth 增加深度标识
     * @param string $p_sub 父级别名
     * @param string $c_sub 深度别名
     * @param string $d_sub 子集别名
     * @return array
     */
    function handleTreeList(?array $arr, int $pid = 0, int $depth = 0, string $p_sub = 'parent_id', string $c_sub = 'children', string $d_sub = 'depth'): array
    {
        $returnArray = [];
        if (is_array($arr) && $arr) {
            foreach ($arr as $k => $v) {
                if ($v[$p_sub] == $pid) {
                    $v[$d_sub] = $depth;
                    $tempInfo = $v;
                    unset($arr[$k]); // 减少数组长度，提高递归的效率，否则数组很大时肯定会变慢
                    $temp = handleTreeList($arr, $v['id'], $depth + 1, $p_sub, $c_sub, $d_sub);
                    if ($temp) {
                        $tempInfo[$c_sub] = $temp;
                    }
                    $returnArray[] = $tempInfo;
                }
            }
        }
        try {
            array_multisort(
                array_column($returnArray, 'order'), SORT_ASC,
                array_column($returnArray, 'id'), SORT_ASC,
                $returnArray
            );
        } catch (\Throwable $throwable) {
        }
        return $returnArray;
    }
}


if (!function_exists('handleMenuTreeList')) {
    /**
     * @param array|null $arr
     * @param int $pid
     * @param int $depth
     * @param string $p_sub
     * @param string $d_sub
     * @return array
     */
    function handleMenuTreeList(?array $arr, int $pid = 0, int $depth = 0, string $p_sub = 'parent_id', string $d_sub = 'depth'): array
    {
        $returnArray = [];
        if (is_array($arr) && $arr) {
            foreach ($arr as $k => $v) {
                if ($v[$p_sub] == $pid) {
                    $v[$d_sub] = $depth;
                    $tempInfo = $v;
                    if ($depth > 0) {
                        $i = 0;
                        $s = '';
                        while ($i < $depth) {
                            $s .= "--";
                            $i++;
                        }
                        $tempInfo['display_name'] = " " . $s . " " . $tempInfo['display_name'];
                    }
                    $returnArray[] = $tempInfo;
                    unset($arr[$k]); // 减少数组长度，提高递归的效率，否则数组很大时肯定会变慢
                    $temp = handleMenuTreeList($arr, $v['id'], $depth + 1, $p_sub, $d_sub);
                    $returnArray = array_merge($returnArray, $temp);
                }
            }
        }
        try {
            array_multisort(
                array_column($returnArray, 'order'), SORT_ASC,
                array_column($returnArray, 'id'), SORT_ASC,
                $returnArray
            );
        } catch (\Throwable $throwable) {
        }
        return $returnArray;
    }
}

if (!function_exists('arrayIndexByKey')) {
    /**
     * 使用二维数组指定 key 的值作为 键生成新的数组
     * @param array $arr
     * @param string $indexKey
     * @return array
     */
    function arrayIndexByKey(array $arr, string $indexKey): array
    {
        return array_combine(array_column($arr, $indexKey), $arr);
    }
}


if (!function_exists('random')) {

    /**
     * 随机字符
     * @param int $length 长度
     * @param string $type 类型
     * @param int $convert 转换大小写
     * @return string
     */
    function random(int $length = 6, string $type = 'string', int $convert = 0): string
    {
        $config = array(
            'number' => '1234567890',
            'letter' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
            'string' => 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ1234567890',
            'lower' => 'abcdefghjkmnpqrstuvwxyz0123456789',
            'upper' => 'ABCDEFGHJKMNPQRSTUVWXYZ0123456789',
            'all' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
        );
        if (!isset($config[$type])) {
            $type = 'string';
        }
        $string = $config[$type];
        $code = '';
        $strLen = strlen($string) - 1;
        for ($i = 0; $i < $length; $i++) {
            $code .= $string[rand(0, $strLen)];
        }
        if (!empty($convert)) {
            $code = ($convert > 0) ? strtoupper($code) : strtolower($code);
        }
        return $code;
    }
}


if (!function_exists('getPageFormParams')) {
    function getPageFormParams(array $params, int $min = 10, $max = 50): array
    {
        $page = (int)@$params['page'] ?: 1;
        $size = (int)@$params['size'] ?: 10;
        $page < 1 && $page = 1;
        $size < $min && $size = $min;
        $size > $max && $size = $max;
        return [$page, $size];
    }
}

if (!function_exists('splitCombineValue')) {
    /**
     * 分解拼接的数据值
     * @param string $value
     * @param bool $isInt
     * @return array
     */
    function splitCombineValue(string $value, bool $isInt = false): array
    {
        $valArr = array_filter(explode(',', $value));
        $isInt && count($valArr) > 0 && $valArr = array_map(function ($v) {
            return (int)$v;
        }, $valArr);
        return $valArr;
    }
}
if (!function_exists('goSleep')) {
    function goSleep(float $seconds): void
    {
        Hyperf\Coroutine\Coroutine::sleep($seconds);
    }
}

if (!function_exists('clearHtml')) {
    function clearHtml(string $value): string
    {
        return strip_tags(html_entity_decode($value));
    }
}
if (!function_exists('vueSortChange')) {
    function vueSortChange(array $params): string
    {
        $value = @$params['sort_method'];
        return $value == "descending" ? "desc" : "asc";
    }
}